package com.wswy.wyjk.ui.practice

import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import android.util.SparseArray
import com.blankj.utilcode.util.SPUtils
import com.raft.framework.arch.SingleLiveData
import com.raft.framework.utils.RxUtils
import com.wswy.wyjk.core.App
import com.wswy.wyjk.model.PracticeData
import com.wswy.wyjk.model.PracticeType
import com.wswy.wyjk.model.RecordData
import com.wswy.wyjk.model.dto.RecordDto
import com.wswy.wyjk.model.vo.PracticeModel
import com.wswy.wyjk.ui.BasePracticeViewModel
import com.wswy.wyjk.ui.practice.exam.ExamCenter
import com.wswy.wyjk.utils.ToastUtils
import io.reactivex.Single
import io.reactivex.functions.BiFunction
import timber.log.Timber
import java.util.concurrent.TimeUnit

class PracticeViewModel : BasePracticeViewModel() {

    private val practiceLiveData = MutableLiveData<List<PracticeModel>?>()

    private val currPracticeLiveData = SingleLiveData<PracticeModel?>()

    private val recordSelectedLiveData = SingleLiveData<Int>()

    //当前的练习
    private val testSession = HashSet<Int>()

    private var lastKey:String?=null

    val uiData = UIPracticeData()

    fun getUndoneCount() = uiData.count - uiData.rightCount - uiData.wrongCount

    override fun onDataLoaderComplete() {
        super.onDataLoaderComplete()

        if(practiceType?.type == PracticeType.TYPE_EXAM_WRONG_LIST){

            loadWithExamWrongs()

        }else{
            ExamCenter.clear()

            lastKey = "last_p_${practiceType?.licenseType?.typeName}_${practiceType?.subjectType?.typeName}_${practiceType?.type}_${practiceType?.chapterId}"

            load()
        }


    }

    private fun load(){

       val type =  practiceType?:return

       val loader =  dataLoader?:return

        //查询所有练习和答题记录

       val toList =  Single.zip(Single.fromCallable {
           loader.allPracticeData
        },Single.fromCallable {
           loader.allRecordData
        },BiFunction<List<PracticeData>?, List<RecordData>?, List<PracticeModel>> { t1, t2 ->

           //合并数据

           val ret =  when(type.type){
               PracticeType.TYPE_EXAM -> createExamData(t1).also {

                   ExamCenter.fillExams(it,type)

               }
               else -> mergeDate(t1,t2)
           }


           ret
        })
           .timeout(5,TimeUnit.SECONDS)
            .compose(RxUtils.io2main())
            .subscribe { t1, t2 ->
                practiceLiveData.postValue(t1)

                t2?.run {
                    Timber.e(this)
                }

            }


        addRun(toList)


    }

    private fun loadWithExamWrongs(){

        val wrongList = ExamCenter.getWrongList()

        wrongList?.forEach {
            testSession.add(it.practiceData.id)
        }

        practiceLiveData.postValue(wrongList)

    }

    private fun mergeDate(t1:List<PracticeData>,t2:List<RecordData>):List<PracticeModel>{
        val ret = ArrayList<PracticeModel>()

        val iteratorP = t1.iterator()
        val iteratorR = t2.iterator()

        val undoneType = practiceType?.type == PracticeType.TYPE_UNDONE

        while (iteratorP.hasNext()){

            val practiceData = iteratorP.next()
            val rData = iteratorR.next()

            val canAdd = !undoneType || (undoneType && !rData.hasAnswer())

            if (canAdd) {

                ret.add(PracticeModel(practiceData).apply {

                    if (iteratorR.hasNext()) {
                        recordData = rData
                    }

                    //初始化已答题数目，统计对错个数
                    if (hasAnswer()) {
                        if (isRight()) {
                            uiData.rightCount++
                        } else {
                            uiData.wrongCount++
                        }

                    }


                })
            }
        }

        //随机练习
        if (practiceType?.type == PracticeType.TYPE_RANDOM){
            ret.shuffle()
        }

        return ret
    }

    //生成考题
    private fun createExamData(list:List<PracticeData>):List<PracticeModel>{
        val retList = ArrayList<PracticeModel>()
        val regulars = dataLoader?.getExamRegular()?:return retList

        val exams = ArrayList<PracticeData>()

        //把所有题目分组 章节 -> 题目类型 -> list
        val allData = SparseArray<MutableMap<Int,MutableList<PracticeData>>>()
        list.forEach {

            var chapters = allData.get(it.chapterId)

            if (chapters == null){
                chapters = HashMap<Int,MutableList<PracticeData>>()

                allData.put(it.chapterId,chapters)
            }

            chapters.getOrPut(it.optionType){
                ArrayList()
            }.add(it)
        }

        val allList1 = ArrayList<PracticeData>()
        val allList2 = ArrayList<PracticeData>()
        val allList3 = ArrayList<PracticeData>()


        regulars.forEach {

            val tmpSet1 = HashSet<PracticeData>(it.count1)

            val cList1 = allData.get(it.chapterId).get(PracticeData.TYPE_RADIO)
            while (it.count1 > 0 && tmpSet1.size != it.count1){
                cList1?.random()?.let {
                    tmpSet1.add(it)
                }
            }

            if (!tmpSet1.isEmpty()){
                allList1.addAll(tmpSet1)
            }


            val tmpSet2 = HashSet<PracticeData>(it.count2)

            val cList2 = allData.get(it.chapterId).get(PracticeData.TYPE_JUDGE)

            while (it.count2 > 0 && tmpSet2.size != it.count2){
                cList2?.random()?.let {
                    tmpSet2.add(it)
                }
            }


            if (!tmpSet2.isEmpty()){
                allList2.addAll(tmpSet2)
            }

            val tmpSet3 = HashSet<PracticeData>(it.count3)

            val cList3 = allData.get(it.chapterId).get(PracticeData.TYPE_MULTIPLE)

            while (it.count3> 0 && tmpSet3.size != it.count3){
                cList3?.random()?.let {
                    tmpSet3.add(it)
                }
            }
            if (!tmpSet3.isEmpty()){
                allList3.addAll(tmpSet3)
            }

        }

        exams.addAll(allList2)
        exams.addAll(allList1)
        exams.addAll(allList3)

        exams.forEach { data ->

            retList.add(PracticeModel(data, RecordData(RecordDto().also {
                it.questionId = data.id
                it.chapterId = data.chapterId
            }, practiceType!!)))

        }


        Timber.e("exam   size ${exams.size}")

        return retList
    }

    /**
     * 添加答题记录
     */
    fun addRecord(model: PracticeModel,option:Int){

        if (option == 0){
            ToastUtils.showText("请选择答案")
            return
        }

        //处理答题结果，记录对错个数
        if (model.hasAnswer()){
            //之前回答过了 已经有过答案

            if (model.isRight() && option != model.practiceData.answer){
                //以前正确 现在不正确了
                uiData.rightCount--
                uiData.wrongCount++

            }else if (!model.isRight() && option == model.practiceData.answer){
                //以前不正确 现在正确
                uiData.rightCount++
                uiData.wrongCount--
            }
        }else{
            //以前没有答过  直接累计
            if (option == model.practiceData.answer){
                uiData.rightCount++
            }else{
                uiData.wrongCount++
            }

        }

        when(practiceType?.type){

            PracticeType.TYPE_ORDER -> {
                model.recordData?.orderAnswer = option
            }

            PracticeType.TYPE_RANDOM -> {
                model.recordData?.randomAnswer = option
            }

            PracticeType.TYPE_CHAPTER -> {
                model.recordData?.chapterAnswer = option
            }

            PracticeType.TYPE_DIFFICULTY -> {
                model.recordData?.difficultAnswer = option
            }
            PracticeType.TYPE_UNDONE -> {
                model.recordData?.undoneAnswer = option
            }
            PracticeType.TYPE_EXAM -> {
                model.recordData?.examAnswer = option
            }
        }

        //已完成状态设置
        model.recordData?.undoneAnswer = option

        testSession.add(model.practiceData.id)

        //非考试状态  保存
        if (practiceType?.type != PracticeType.TYPE_EXAM){
            App.daoSession?.saveRecord(model.recordData?.dtoRef)
        }


        currPracticeLiveData.postValue(model)

    }

    fun getPracticeLiveData():LiveData<List<PracticeModel>?> = practiceLiveData

    fun getCurrPracticeLiveData():LiveData<PracticeModel?> = currPracticeLiveData

    fun getRecordSelectedLiveData():LiveData<Int> = recordSelectedLiveData


    //添加到当前已做
    fun alreadyReply(questionId: Int): Boolean {
        return testSession.contains(questionId)
    }

    fun isExamMode() = practiceType?.type == PracticeType.TYPE_EXAM || practiceType?.type == PracticeType.TYPE_EXAM_WRONG_LIST

    fun saveSession(position:Int){

        val key = lastKey?:return

        //保存上次练习位置

        when(practiceType?.type){
            PracticeType.TYPE_ORDER,PracticeType.TYPE_CHAPTER,PracticeType.TYPE_DIFFICULTY,PracticeType.TYPE_ERROR -> {
                //顺序练习 章节练习 难题
                SPUtils.getInstance().put(key,position)
            }
        }

    }

    fun getLastPosition():Int{
        val key = lastKey?:return 0
        return SPUtils.getInstance().getInt(key,0)
    }


    fun onRecordDismiss(position: Int){
        recordSelectedLiveData.postValue(position)
    }

}